<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Bable-JSX</title>
  <style>
  table{
    border-collapse:collapse;
  }
  table,th,td{
    border: 1px solid black;
  }
  </style>
</head>
<body>
  <div id="app"></div>
  <script type="text/javascript" src="../js/react.js"></script>
  <script type="text/javascript" src="../js/react-dom.js"></script>
  <script type="text/javascript" src="../babel/browser.js"></script>
  <script type="text/babel">
  var header = ["Book","Author","Language"];
  var exceldata = [["Think in java","janmes","JAVA"],["C++ Permier","zhang san","C++"],["python编程思想","wang wu","python"]];

  var excel = React.createClass({
    displayName: 'excel',
    propTypes: {
      header: React.PropTypes.array,
    },
    getInitialState: function() {
      return {
        header: this.props.header,
        data: this.props.initdata,
        sortby: null,
        descending: false,//降序默认是false，也就是默认升序排序
        search: false,
      };
    },

    _sort:function(ev) {
      var column = ev.target.cellIndex;
      // this.state.sortby = column;  //错误的赋值方式，如果要设置state里的sortby，需要通过setState()方法设置

      // 只有当排序字段是同一字段，且，当前排序方式不是降序的时候，才进行降序排序
      var isDesc = this.state.sortby === column && !this.state.descending

      // slice()是数组的深度拷贝
      var sortdata = this.state.data.slice();
      // 数组的sort()方法，默认是按照ASIIC的先后循序排序，如果要按其他的方式排序，需要传入一个函数作为参数，函数传输两个参数，返回两个参数比较的大小
      sortdata.sort(function(a, b) {
        return isDesc
         ? (a[column] < b[column] ? 1 : -1)//降序排列
         : (a[column] < b[column] ? -1 : 1)//升序排列
      });

      this.setState({
        data: sortdata,
        sortby: column,//这样对state的赋值方式才正确
        descending: isDesc,
        editIdex: null,//{row: rowIdex, cell: cellIndex}
      });
    },

    _showEdit: function(ev) {
      this.setState({
        editIdex: {
          row: parseInt(ev.target.dataset.row, 10),
          cell: ev.target.cellIndex,
        }
      });
    },

    _save: function(ev) {
      ev.preventDefault();
      var input = ev.target.firstChild;
      var data = this.state.data.slice();

      data[this.state.editIdex.row][this.state.editIdex.cell] = input.value;

      this.setState({
        editIdex: null,
        data: data,
      })
    },


    // 渲染table组件
    _renderTable: function() {
        var state = this.state;
        return (
          <table>
            <thead>
              {this._renderSearch()}
              <tr onClick={this._sort}>
                {
                    this.state.header.map(function(title, idx) {
                    var sortby = this.state.sortby;
                    if( sortby === idx) {
                      title = title + (this.state.descending ? ' \u2193': ' \u2191');
                    }
                    return <td key={idx}>{title}</td>
                  }, this)
                }
              </tr>
            </thead>
            <tbody>
              {
                this.state.data.map(function(row, rowidx) {
                  return (
                    <tr key={rowidx} onDoubleClick={this._showEdit}>
                      {
                        row.map(function(cell, idx) {
                          var context = cell;
                          var editposite = this.state.editIdex;

                          if(editposite && rowidx === editposite.row && idx === editposite.cell) {
                            context = <form onSubmit={this._save}><input type='text' defaultValue={cell} /></form>
                            console.log("======== " + context);
                          }

                          return (<td key={idx} data-row={rowidx}>{context}</td>)
                        }, this)
                      }
                    </tr>
                    )
                }, this)
              }
            </tbody>
          </table>
        )


        // row.map(function(cell, idx) {
        //   // var context = cell;
        //   // var editposite = this.state.editIdex;
        //   // if(editposite && rowid === editposite.row && idx === editposite.cell) {
        //   //   context = <form onSubmit={this._save}><input type="text" value={cell} /></form>
        //   // }
        //   //
        //   // return <td key={idx} data-row={rowidx}>{context}</td>
        //   return (<td key={idx} data-row={rowidx}>{cell}</td>);
        // }, this)
        //

      // return React.DOM.table(null,
      //   // thead
      //   React.DOM.thead(null,
      //     // this._renderSearch(),//这里会判断search开关，打开时渲染search搜索框
      //     this._renderSearch(),
      //     React.DOM.tr({onClick: this._sort},
      //       this.state.header.map(function(title, idx){
      //         var sortby = this.state.sortby;
      //         if( sortby === idx) {
      //           title = title + (this.state.descending ? ' \u2193': ' \u2191');
      //         }
      //         return React.DOM.th({key: idx}, title);
      //       }, this)//注意，这里要传入this，否则回调函数里，是不知道外边对象的，也就是回调函数里的this是undefined
      //     )
      //   ),
      //   tbody
      //   React.DOM.tbody({onDoubleClick: this._showEdit},//_showEdit函数的意义就在于，根据事件源定义双击单元格的坐标，然后重新render整个table，render table时下边就根据定位坐标渲染文本框
      //     this.state.data.map(function(row, rowid){
      //       return React.DOM.tr({key: rowid},
      //         row.map(function(cell, idx) {
      //           var content = cell;
      //           var editflag = this.state.editIdex;
      //           if(editflag && rowid === editflag.row && idx === editflag.cell) {
      //             content = React.DOM.form({onSubmit: this._save},  //将react组件赋值给 context，这样td在渲染的时候，可以渲染文字，可以渲染子组件
      //               React.DOM.input({type: 'text', defaultValue: content})
      //             );
      //           }
      //
      //           return React.DOM.td(
      //             {
      //               key: idx,
      //               'data-row': rowid
      //             },
      //             content);//这个context也许是文字，也许是组件
      //         }, this)//这个this，是下边传进来的this对象
      //       );
      //     }, this)
      //   )
      // )

    },

    // 这个组件仅渲染一个button 和一个onclick事件
    _renderToolbar: function() {
      return <button type="button" onClick={this._toggleSearch} className='toolbar'>
              {this._changeText()}
            </button>
    },

    _changeText: function() {
      if(this.state.search) {
        return "关闭";
      } else {
        return "打开";
      }
    },

    // 定义一个_preSearchData对象，存储原来的表格数据，防止表格过滤后不能恢复到原来的数据
    _preSearchData: null,

    // 切换开关，主要是切换 search 开关，是否显示搜索框。调用setState，重新渲染render方法，也就调用了rendertable。
    _toggleSearch: function() {
      if(this.state.search) {
        this.setState({
          data: this._preSearchData,
          search: false,
        })
        this._preSearchData = null;
      } else {
        this._preSearchData = this.state.data;
        this.setState({
          search: true,
        });
      }
    },

    // _renderSearchInput: function() {
    //   return React.DOM.tr(null,
    //     React.DOM.td(null,
    //       React.DOM.input({type: 'text'})
    //     )
    //   )
    // },

    // 调用rendertable时，就会调用这里，如果search开关打开，就渲染一行搜索文本框
    _renderSearch: function() {
      var state = this.state;
      var props = this.props;

      if(!state.search) {
        return null;
      };

      return (
        <tr onChange={this._search}>
            {
              this.state.header.map(function(_ingrol, idx){
                return <td key={idx}><input type="text" data-idx={idx} /></td>
              })
            }
        </tr>
      )
    },
    // 定义了当搜索文本框onchange后，进行数组的filter
    _search: function(ev) {
      // 获取事件源文本框的文本
      var needle = ev.target.value.toLowerCase();
      if(!needle) {
        this.setState({
          data: this._preSearchData,
        });
        return;
      }
      // 通过dataset，获取事件源是第几个td
      var evidx = ev.target.dataset.idx;
      var mubiaoarr = this._preSearchData.filter(function(row){
        return row[evidx].toString().toLowerCase().indexOf(needle) > -1;
      });

      this.setState({
        data: mubiaoarr,
      });
    },

    // 整个组件的渲染方法入口
    render: function(){
      return (
        React.DOM.div(null,
          this._renderToolbar(),
          this._renderTable()
        )
      );
    }
  });

  ReactDOM.render(
    // 用自定义组建创建
    // 直接用React.createElement(标签, 属性, 子元素),
    // React.createElement("span", null, "this is 直接创建 element"),
    React.createElement(excel, {
      header: header,
      initdata: exceldata,
    }),
    document.getElementById("app")
  )
  </script>
</body>
</html>
